/*
 * Created by Jaren at 2021/10/29 10:50
 */
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:ble_plugin/ble_plugin.dart';
import 'package:get/get.dart';
import 'package:inmotion_protocol/base/file/file_manager.dart';
import 'package:inmotion_protocol/base/vehicle_data.dart';
import 'package:inmotion_protocol/common/exceptions.dart';
import 'package:inmotion_protocol/common/log_file_manager.dart'
    as log_file_manager;
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/response.dart';
import 'package:inmotion_protocol/common/vehicle_info.dart';
import 'package:inmotion_protocol/ezcan/bean/ebike/ebike_settings.dart';
import 'package:inmotion_protocol/lorin/bean/base/tbox.dart';
import 'package:inmotion_protocol/lorin/bean/common/response/response.dart';
import 'package:inmotion_protocol/lorin/bean/scooter/s1/s1_settings.dart';
import 'package:inmotion_protocol/lorin/constant.dart';
import 'package:inmotion_protocol/lorin/factory/general/general_message.factory.dart';
import 'package:inmotion_protocol/lorin/factory/lorin_message_factory.dart';
import 'package:inmotion_protocol/lorin/lorin_message.dart';
import 'package:inmotion_protocol/lorin/media/avatar_file_manager.dart'
    hide FileTransferringEvent;
import 'package:inmotion_protocol/util/byte_util.dart';
import 'package:inmotion_protocol/util/device.dart';
import 'package:inmotion_protocol_example/module/audio/audio_pkg_controller.dart';
import 'package:inmotion_protocol_example/module/audio/audio_pkg_view.dart';
import 'package:inmotion_protocol_example/module/base/base.dart';
import 'package:inmotion_protocol/handler/send_handler.dart';
import 'package:inmotion_protocol/inmotion_protocol.dart';
import 'package:inmotion_protocol/protocol_worker.dart';
import 'package:inmotion_protocol/util/log.dart';
import 'package:inmotion_protocol_example/module/fw_update/fm_update_view.dart';
import 'package:inmotion_protocol_example/module/fw_update/fw_update_controller.dart';
import 'package:inmotion_protocol_example/module/light_effect/light_effect_pkg_controller.dart';
import 'package:inmotion_protocol_example/module/light_effect/light_effect_pkg_view.dart';
import 'package:inmotion_protocol_example/module/widget/prompt.dart';
import 'package:path_provider/path_provider.dart';
import 'package:inmotion_protocol/common/bms_log_manager.dart'
    as bms_log_manager;

class OperationController extends BaseController {
  RxInt speed = 0.obs;

  InMotionProtocol protocol = InMotionProtocol();

  ProductProperty? _productProperty;

  @override
  void init() {
    BleManager().onNotifiedCallback = (device, values) {
      Uint8ClampedList bytes = Uint8ClampedList.fromList(values);
      LogUtils.d('onDataReceived, ' + ByteUtil.bytes2HexString(bytes));
      protocol.onDataReceived(bytes);
    };

    protocol.preInit(
      BleSendHandler(),
      Platform.isAndroid ? 200 : 144,
      deviceName: BleManager().activeDevices.values.first.device.name,
    );

    protocol.setUnhandledMsgHandler((msg) {
      print("unhandled msg: $msg");
      return false;
    });

    String deviceName = BleManager().activeDevices.values.first.device.name;
    LogUtils.d("Current device name is $deviceName");

    BleManager().config(InMotionProtocol.getDeviceConfig(deviceName));

    protocol.onLinkLayerConnected(deviceName).then((value) {
      requestProductProperty();
    });

    Get.put(protocol, tag: 'protocol');
  }

  void requestProductProperty() {
    protocol.requestProductProperty().then((property) {
      LogUtils.d(property.toString());
      _productProperty = property;
      protocol.init(property.model, property.versionWrapper);

      requestDevicesId();

      Future.delayed(
          const Duration(milliseconds: 500), () => protocol.syncRTC());

      Get.put(_productProperty, tag: 'product_property');
    }).catchError((e) {
      if (e is RequestProductPropertyFailedException) {
        LogUtils.e("requestProductProperty error, ${e.formatErrorCode()}");
        return;
      }
      LogUtils.e(
        "Unknown exception, ${e.toString()}",
      );
    });
  }

  void requestDevicesId() {
    LogUtils.e("requestDevicesId");
    protocol
        .requestDevicesId(DeviceUtils.allDevices(_productProperty!.model))
        .then((deviceWrapper) {
      LogUtils.d("devices id : " + deviceWrapper.devices.toString());
    });
  }

  void requestAccessories() {
    LogUtils.e("requestAccessories");
    protocol.requestAccessoriesInfo().then((accessoriesWrapper) {
      LogUtils.d(
          "accessories info : " + accessoriesWrapper.accessories.toString());
    });
  }

  void requestTotalStatistics() {
    protocol.requestTotalStatistics().then((totalStatistics) {
      LogUtils.d(totalStatistics.toString());
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("requestTotalStatistics timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void requestCurrentHistoryStatistics() {
    protocol.requestCurrentStatistics().then((statistics) {
      LogUtils.d(statistics.toString());
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("requestCurrentHistoryStatistics timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void requestHistoryStatistics(int fromId) {
    var helper = protocol.createRidingStatisticsHelper();
    helper.request(fromId: fromId).then((List<HistoryStatistics> list) {
      LogUtils.d("list count: ${list.length}, data: ${list.toString()}");
    });
  }

  void buildSecurityConnection() {
    protocol.buildSecurityConnection().then((b) {
      LogUtils.e("buildSecurityConnection success");
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("buildSecurityConnection timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void activate() {
    protocol.activate().then((success) {
      LogUtils.d("activate, result: $success");
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("activate timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void volume(int volume) {
    protocol.setVolume(volume).then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("Success");
      } else {
        LogUtils.v("Failed");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("volume timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void driveMode(int mode) {
    protocol.setDriveMode(mode).then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("Success");
      } else {
        LogUtils.v("Failed");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("driveMode  timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void speedLimit(int speed) {
    protocol.setSpeedLimit(speed).then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("Success");
      } else {
        LogUtils.v("Failed");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("speedLimit  timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void lock(bool lock) {
    protocol.lock(lock).then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("lock success");
        Prompt.showToast("Success", "Succeed");
      } else {
        LogUtils.v("lock failed");
        Prompt.showToast("Fail", "Failed[${rsp.error}]");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("lock on/off timeout");
        Prompt.showToast("Fail", "Response timeout");
        return;
      }
      LogUtils.e("Unknown exception, lock, " + e.toString());
      Prompt.showToast("Fail", "Unknown error.[${e.toString()}]");
    });
  }

  void transportationMode(bool on) {
    protocol.transportationModeOnOff(on).then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("Success");
      } else {
        LogUtils.v("Failed");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("transportationMode on/off timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void headlight(bool on) {
    protocol.headlightOnOff(on: on).then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("Success");
      } else {
        LogUtils.v("Failed");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("headlight on/off timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void headlight2(bool low, bool high) {
    protocol.headlightOnOff(lowBeamOn: low, highBeamOn: high).then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("Success");
      } else {
        LogUtils.v("Failed");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("headlight on/off timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void headlightBrightness(
      {int? brightness, int? lowBeamBrightness, int? highBeamBrightness}) {
    protocol
        .setHeadlightBrightness(
            brightness: brightness,
            lowBeamBrightness: lowBeamBrightness,
            highBeamBrightness: highBeamBrightness)
        .then((rsp) {
      LogUtils.d(rsp.toString());
      if (rsp.isSuccess()) {
        LogUtils.v("headlightBrightness, Success");
      } else {
        LogUtils.v("headlightBrightness, Failed");
      }
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("headlightBrightness, timeout");
        return;
      }
      LogUtils.e("headlightBrightness, Unknown exception, " + e.toString());
    });
  }

  void requestRealTimeState() {
    protocol.requestRealTimeState().then((rsp) {
      LogUtils.d(rsp.toString());
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("requestRealTimeState timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void requestRealTimeInfo() {
    protocol.requestRealTimeInfo().then((rsp) {
      LogUtils.d(rsp.toString());
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("requestRealTimeInfo timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void requestRealTimeError() {
    protocol.requestRealTimeError().then((rsp) {
      LogUtils.d(rsp.toString());
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("requestRealTimeError timeout");
        return;
      }
      LogUtils.e("Unknown exception, " + e.toString());
    });
  }

  void requestAllRealTimeInfo() {
    protocol.requestAllRealTimeData().then((rsp) {
      LogUtils.d("battery level: " +
          rsp.realTimeInfo.batteryLevel.toString() +
          ", pc mode: ${rsp.realTimeState.pcMode}, pc mode value: ${rsp.realTimeState.pcModeValue.value}, lock state: ${rsp.realTimeState.lockState.value}");
      LogUtils.d(rsp.toString());
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("requestAllRealTimeData timeout");
        return;
      }
      LogUtils.e(
          "Unknown exception when requestAllRealTimeData, " + e.toString());
    });
  }

  void requestBatteryRealTimeInfo() {
    protocol.requestBatteryRealTimeInfo().then((batteryRealTimeInfo) {
      LogUtils.d(
          "requestBatteryRealTimeInfo, " + batteryRealTimeInfo.toString());
    }).catchError((e) {
      if (e is MsgTimeoutException) {
        LogUtils.e("requestBatteryRealTimeInfo timeout");
        return;
      }
      LogUtils.e(
          "Unknown exception when requestBatteryRealTimeInfo, " + e.toString());
    });
  }

  void requestSettings() {
    protocol.requestSettings().then((settings) {
      if (settings is P2LikeSettings) {
        assistanceSettings = settings.assistanceSettings;
      }
      LogUtils.d("requestSettings, settings->" + settings.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when requestSettings, $e", e);
    });
  }

  void setPitchAngleZero(int angleZ) {
    protocol.setPitchAngleZero(angleZ).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setPedalSensitivity, success");
        return;
      }
      LogUtils.d("setPedalSensitivity, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setPedalSensitivity", e);
    });
  }

  void setPedalSensitivity(int sensitivity1, int sensitivity2) {
    protocol.setPedalSensitivity(sensitivity1, sensitivity2).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setPedalSensitivity, success");
        return;
      }
      LogUtils.d("setPedalSensitivity, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setPedalSensitivity", e);
    });
  }

  void lowBatterySafeMode(bool on) {
    protocol.lowBatLevelProtectionModeOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("lowBatterySafeMode, success");
        return;
      }
      LogUtils.d("lowBatterySafeMode, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when lowBatterySafeMode", e);
    });
  }

  void setStandbyTime(int seconds) {
    protocol.setStandbyTime(seconds).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setStandbyTime, success");
        return;
      }
      LogUtils.d("setStandbyTime, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setPedalSensitivity", e);
    });
  }

  void setSpeedingBrakingOnOff(bool on) {
    protocol.speedingBrakingOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setSpeedingBrakingOnOff, success");
        return;
      }
      LogUtils.d("setSpeedingBrakingOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e(
          "Error occurred when setSpeedingBrakingOnOff, " + e.toString(), e);
    });
  }

  void overSpeedWarningOnOff(bool on) {
    protocol.overSpeedWarningOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("overSpeedWarningOnOff, success");
        return;
      }
      LogUtils.d("overSpeedWarningOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e(
          "Error occurred when overSpeedWarningOnOff, " + e.toString(), e);
    });
  }

  void powerOnOff(bool on) {
    protocol.powerOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("powerOnOff, success");
        return;
      }
      LogUtils.d("powerOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when powerOnOff, " + e.toString(), e);
    });
  }

  void gpsOnOff(bool on) {
    protocol.gpsOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("gpsOnOff, success");
        return;
      }
      LogUtils.d("gpsOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when gpsOnOff, " + e.toString(), e);
    });
  }

  void bermAngleModeOnOff(bool on) {
    protocol.bermAngleModeOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("bermAngleModeOnOff, success");
        return;
      }
      LogUtils.d("bermAngleModeOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when bermAngleModeOnOff, " + e.toString(), e);
    });
  }

  void setLanguage(int language) {
    protocol.setLanguage(language).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setLanguage, success");
        return;
      }
      LogUtils.d("setLanguage, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setLanguage, " + e.toString(), e);
    });
  }

  void turningSensitivity(int sensitivity) {
    protocol.setTurningSensitivity(sensitivity).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("turningSensitivity, success");
        return;
      }
      LogUtils.d("turningSensitivity, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when turningSensitivity, " + e.toString(), e);
    });
  }

  void lightEffectOnOff(bool on) {
    if (_productProperty != null && _productProperty!.model.isLS1Series()) {
      protocol.requestSettings().then((value) {
        protocol
            .setLightEffectMode(
                mode: S1Settings.calLightEffectMode(
                    (value as S1Settings).lightEffectMode.value,
                    lightEffectOnOff: on))
            .then((rsp) {
          if (rsp.isSuccess()) {
            LogUtils.d("lightEffectOnOff, success");
            return;
          }
          LogUtils.d("lightEffectOnOff, failed, " + rsp.error.toString());
        }).catchError((e) {
          LogUtils.e(
              "Error occurred when setSpeedingBrakingOnOff, " + e.toString(),
              e);
        });
      });

      return;
    }
    protocol.setLightEffectMode(onOff: on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("lightEffectOnOff, success");
        return;
      }
      LogUtils.d("lightEffectOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e(
          "Error occurred when setSpeedingBrakingOnOff, " + e.toString(), e);
    });
  }

  void setLightEffectId(int id, [int color = 0]) {
    protocol.setLightEffectId(id).then((rsp) {
      print(rsp);
    }).onError((error, stackTrace) {
      stackTrace.printError();
    });

    // protocol.setLightEffectId(id, color).then((rsp) {
    //   if (rsp.isSuccess()) {
    //     LogUtils.d("setLightEffectId, success");
    //     return;
    //   }
    //   LogUtils.d("setLightEffectId, failed, " + rsp.error.toString());
    // }).catchError((e) {
    //   LogUtils.e("Error occurred when setLightEffectId, " + e.toString(), e);
    // });
  }

  void setLightEffectOnOff(bool on) {
    protocol
        .setLightEffectMode(
            mode: S1Settings.calLightEffectMode(0, lightEffectOnOff: on))
        .then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setLightEffectOnOff, success");
        return;
      }
      LogUtils.d("setLightEffectOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setLightEffectOnOff, " + e.toString(), e);
    });
  }

  void soundPackOnOff(bool on) {
    protocol.soundPackOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("soundPackOnOff, success");
        return;
      }
      LogUtils.d("soundPackOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e(
          "Error occurred when setSpeedingBrakingOnOff, " + e.toString(), e);
    });
  }

  void soundWaveOnOff(bool on) {
    protocol.soundWaveOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("soundWaveOnOff, success");
        return;
      }
      LogUtils.d("soundWaveOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when soundWaveOnOff, " + e.toString(), e);
    });
  }

  void horn() {
    protocol.horn().then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("horn, success");
        return;
      }
      LogUtils.d("horn, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when horn, " + e.toString(), e);
    });
  }

  void factoryReset(int level) {
    protocol.factoryReset(level: level).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("factoryReset, success");
        return;
      }
      LogUtils.d("factoryReset, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when factoryReset, " + e.toString(), e);
    });
  }

  void cruiseOnOff(bool on) {
    protocol.cruiseOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("cruiseOnOff, success");
        return;
      }
      LogUtils.d("cruiseOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when cruiseOnOff, " + e.toString(), e);
    });
  }

  void spinKillOnOff(bool on) {
    protocol.spinKillOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("spinKillOnOff, success");
        return;
      }
      LogUtils.d("spinKillOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when spinKillOnOff, " + e.toString(), e);
    });
  }

  void setFrontRearBrakeForce(int force) {
    protocol.setBrakeForce(force).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setFrontRearBrakeForce[$force], success");
        return;
      }
      LogUtils.d(
          "setFrontRearBrakeForce[$force], failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setFrontRearBrakeForce[$force]", e);
    });
  }

  AssistanceSettings? assistanceSettings;

  void setRidingMode(int mode) {
    protocol.setRidingMode(mode, assistanceSettings).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setRidingMode[$mode], success");
        return;
      }
      LogUtils.d("setRidingMode[$mode], failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setRidingMode[$mode]", e);
    });
  }

  void setAssistantMode(int mode) {
    protocol.setAssistantMode(mode, assistanceSettings).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setAssistantMode[$mode], success");
        return;
      }
      LogUtils.d("setAssistantMode[$mode], failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setAssistantMode[$mode]", e);
    });
  }

  void zeroSpeedStartupOnOff(bool on) {
    protocol.zeroSpeedupOnOff(on, assistanceSettings).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("zeroSpeedStartupOnOff, success");
        return;
      }
      LogUtils.d("zeroSpeedStartupOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e(
          "Error occurred when zeroSpeedStartupOnOff, " + e.toString(), e);
    });
  }

  void setSpeedUnit(int unit) {
    protocol.setSpeedUnit(unit).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setSpeedUnit, success");
        return;
      }
      LogUtils.d("setSpeedUnit, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setSpeedUnit, " + e.toString(), e);
    });
  }

  void forceUpdate() {
    protocol.writeForceUpdate(2, "1.2.46", "1.2.46").then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setSpeedUnit, success");
        return;
      }
      LogUtils.d("setSpeedUnit, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when setSpeedUnit, " + e.toString(), e);
    });
  }

  void gotoUpdateFw() {
    Get.to(FwUpdatePage(), binding: BindingsBuilder(() {
      Get.put(FwUpdateController());
    }));
  }

  void gotoUploadAudioPkg() {
    Get.to(AudioPkgUploadPage(), binding: BindingsBuilder(() {
      Get.put(AudioPkgController());
    }));
  }

  void getAudioIdList() {
    protocol.getSoundPackIdList().then((idList) {
      LogUtils.d("getAudioIdList, list, " + idList.toString());
    }).onError((error, stackTrace) {
      LogUtils.e("", error);
    });
  }

  void getAudioItemIndexList() {
    protocol.getSoundItemIndexList().then((idList) {
      LogUtils.d("getSoundItemIndexList, list, " + idList.toString());
    }).onError((error, stackTrace) {
      LogUtils.e("", error);
    });
  }

  void gotoUploadLightEffectPkg() {
    Get.to(LightEffectPkgUploadPage(), binding: BindingsBuilder(() {
      Get.put(LightEffectPkgController());
    }));
  }

  void getLightEffectIdList() {
    protocol.getLightEffectPkgIdList().then((idList) {
      LogUtils.d("getLightEffectIdList, list, " + idList.toString());
    }).onError((error, stackTrace) {
      LogUtils.e("", error);
    });
  }

  void setPasswordType(int type) {
    protocol.setPasswordType(type).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("setPasswordType,  successfully");
      } else {
        LogUtils.d("setPasswordType, error  " + rsp.error.toString());
      }
    });
  }

  void requestBMSFixedInfo() {
    if (_productProperty!.model.isV13Series() ||
        _productProperty!.model.isV11Y() ||
        _productProperty!.model.isV12sSeries() ||
        _productProperty!.model.isV9Series() ||
        _productProperty!.model.isP6Series()) {
      protocol
          .requestBMSFixedInfo(DeviceUtils.lorinVBMS1Device)
          .then((bmsFixedInfo1) {
        LogUtils.d(
            "requestBMSFixedInfo, fixed info 1: ${bmsFixedInfo1.toString()}");
        protocol.requestBMSFixedInfo(DeviceUtils.lorinVBMS2Device).then(
            (bmsFixedInfo2) => {
                  LogUtils.d(
                      "requestBMSFixedInfo, fixed info 2: ${bmsFixedInfo2.toString()}")
                });
      });
    } else if (_productProperty!.model.isLR1Series() ||
        _productProperty!.model.isRSVeloSeries()) {
      protocol.requestBMSFixedInfo(DeviceUtils.lorinLR1BmsDevice).then(
          (bmsFixedInfo) => {
                LogUtils.d(
                    "requestBMSFixedInfo, fixed info: ${bmsFixedInfo.toString()}")
              });
    }
  }

  void requestBMSCellsVoltage() {
    if (_productProperty!.model.isV13Series() ||
        _productProperty!.model.isV11Y() ||
        _productProperty!.model.isV12sSeries() ||
        _productProperty!.model.isV9Series() ||
        _productProperty!.model.isP6Series()) {
      protocol.requestBMSCellsVoltage(DeviceUtils.lorinVBMS1Device).then(
          (cellsVoltage1) => protocol
              .requestBMSCellsVoltage(DeviceUtils.lorinVBMS2Device)
              .then((cellsVoltage2) => {
                    LogUtils.d(
                        "requestBMSCellsVoltage, cells1 voltage: ${cellsVoltage1.toString()}, cells2 voltage: ${cellsVoltage2.toString()}")
                  }));
    } else if (_productProperty!.model.isLE1Series()) {
      protocol.requestBMSCellsVoltage(DeviceUtils.lorinScooterBtDevice).then(
          (cellsVoltage) => {
                LogUtils.d(
                    "requestBMSCellsVoltage, cells voltage: ${cellsVoltage.toString()}")
              });
    } else if (_productProperty!.model.isLR1Series() ||
        _productProperty!.model.isRSVeloSeries()) {
      protocol.requestBMSCellsVoltage(DeviceUtils.lorinLR1BmsDevice).then(
          (cellsVoltage) => {
                LogUtils.d(
                    "requestBMSCellsVoltage, cells voltage: ${cellsVoltage.toString()}")
              });
    }
  }

  void requestBMSRealTimeInfo() {
    if (_productProperty!.model.isV13Series() ||
        _productProperty!.model.isV11Y() ||
        _productProperty!.model.isV12sSeries() ||
        _productProperty!.model.isV9Series() ||
        _productProperty!.model.isP6Series()) {
      protocol.requestBMSRealTimeInfo(DeviceUtils.lorinVBMS1Device).then(
          (bmsRealTimeInfo1) => protocol
              .requestBMSRealTimeInfo(DeviceUtils.lorinVBMS2Device)
              .then((bmsRealTimeInfo2) => {
                    LogUtils.d(
                        "requestBMSRealTimeInfo, bms1 realtime info: ${bmsRealTimeInfo1.toString()}, bms2 realtime info: ${bmsRealTimeInfo2.toString()}")
                  }));
    } else if (_productProperty!.model.isLR1Series() ||
        _productProperty!.model.isRSVeloSeries()) {
      protocol
          .requestBMSRealTimeInfo(DeviceUtils.lorinLR1BmsDevice)
          .then((bmsRealTimeInfo) => {
                LogUtils.d(
                    "requestBMSRealTimeInfo, bms1 realtime info: ${bmsRealTimeInfo.toString()}")
              });
    }
  }

  void startMotorAutoCompat() {
    protocol.startCalibration(Constant.calibrationMotorAutoCompat).then((rsp) {
      LogUtils.d("startMotorAutoCompat, succeed?${rsp.isSuccess()}");
    });
  }

  void queryMotorAutoCompatResult() {
    protocol
        .queryCalibrationResult(Constant.calibrationMotorAutoCompat)
        .then((result) {
      result as MotorAutoCalibrateResultResponse;
      LogUtils.d(
          "queryMotorAutoCompatResult, hallOffsetCompatState: ${result.hallOffsetCompatState}, hallSectorCompatState: ${result.hallSectorCompatState}");
    });
  }

  void startMotorSelfCheck() {
    protocol.startCalibration(Constant.calibrationMotorSelfCheck).then((rsp) {
      LogUtils.d("startMotorSelfCheck, succeed?${rsp.isSuccess()}");
    });
  }

  void queryMotorSelfCheckResult() {
    protocol
        .queryCalibrationResult(Constant.calibrationMotorSelfCheck)
        .then((result) {
      result as MotorSelfCheckResultResponse;
      LogUtils.d("queryMotorSelfCheckResult, state: ${result.state}");
      if (result.isCalibrating()) {
        LogUtils.d("queryMotorSelfCheckResult, checking...");
      }
      if (result.isCalibrateFailed()) {
        LogUtils.d("queryMotorSelfCheckResult, check failed");
      }
      if (result.isCalibrateSucceed()) {
        LogUtils.d("queryMotorSelfCheckResult, check succeed.");
      }
    });
  }

  void startBatteryCalibration() {
    protocol.startCalibration(Constant.calibrationBatteryVoltage).then((rsp) {
      LogUtils.d("startBatteryCalibration, succeed?${rsp.isSuccess()}");
    });
  }

  void queryBatteryCalibrationResult() {
    protocol
        .queryCalibrationResult(Constant.calibrationBatteryVoltage)
        .then((result) {
      result as BatteryCalibrationResultResponse;
      LogUtils.d("queryBatteryCalibrationResult, state: ${result.state}");
      if (result.isCalibrating()) {
        LogUtils.d("queryBatteryCalibrationResult, checking...");
      }
      if (result.isCalibrateFailed()) {
        LogUtils.d("queryBatteryCalibrationResult, check failed");
      }
      if (result.isCalibrateSucceed()) {
        LogUtils.d("queryBatteryCalibrationResult, check succeed.");
      }
    });
  }

  void calibrateAccHandle() {
    protocol.startCalibration(Constant.calibrationAccHandle).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("calibrateAccHandle, start successfully");
      } else {
        LogUtils.d("calibrateAccHandle, error  " + rsp.error.toString());
      }
    });
  }

  void calibrateBrakeHandle() {
    protocol.startCalibration(Constant.calibrationBrakeHandle).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("calibrateBrakeHandle, start successfully");
      } else {
        LogUtils.d("calibrateBrakeHandle, error  " + rsp.error.toString());
      }
    });
  }

  void queryHandleCalibrationResult(int which) {
    protocol.queryCalibrationResult(which).then((rsp) {
      rsp as ScooterCalibrationResultResponse;
      String result = 'unknown';
      if (rsp.isCalibrateSucceed()) {
        result = 'succeed';
      } else if (rsp.isCalibrateFailed()) {
        result = 'failed';
      } else if (rsp.isCalibrating()) {
        result = 'calibrating';
      } else if (rsp.isCalibrateTimeout()) {
        result = 'calibrate timeout';
      }
      LogUtils.d("queryHandle1CalibrationResult: $result");
    });
  }

  void startScooterIMUCalibration() {
    protocol.startCalibration(Constant.calibrationScooterIMUHandle).then((rsp) {
      if (!rsp.isSuccess()) {
        LogUtils.d("startTurningCalibration failed, " + rsp.error.toString());
        return;
      }
    });
  }

  void startTurningCalibration() {
    protocol.startCalibration(Constant.calibrationTurning).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("startTurningCalibration success");
      } else {
        LogUtils.d("startTurningCalibration failed, " + rsp.error.toString());
      }
    });
  }

  void startBalanceCalibration() {
    protocol.startCalibration(Constant.calibrationBalance).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("startBalanceCalibration success");

        Future.delayed(Duration(milliseconds: 50), () {
          queryBalanceCalibrationResult();
        });
      } else {
        LogUtils.d("startBalanceCalibration failed, " + rsp.error.toString());
      }
    });
  }

  void queryTurningCalibrationResult() {
    protocol.queryCalibrationResult(Constant.calibrationTurning).then((rsp) {
      rsp as EUCIMUCalibrationResultResponse;
      LogUtils.d(
          "queryTurningCalibrationResult: ${rsp.result0}, ${rsp.result1}, ${rsp.result2}");
    });
  }

  void queryBalanceCalibrationResult() {
    protocol.queryCalibrationResult(Constant.calibrationBalance).then((rsp) {
      rsp as EUCIMUCalibrationResultResponse;
      LogUtils.d(
          "queryBalanceCalibrationResult: ${rsp.result0}, ${rsp.result1}, ${rsp.result2}");
    });
  }

  void requestAvatar() {
    var manager = protocol.createAvatarFileManager();

    getApplicationDocumentsDirectory().then((dir) {
      manager.downloadConfig(
          LorinAvatarFileConfig.create(dir.path + "/avatar/user.jpg"));

      manager.download().listen((event) {
        LogUtils.d('requestAvatar, type: ${event.type}');
        switch (event.type) {
          case Event.typeFileTransferring:
            break;
          case Event.typeFileTransferFinished:
            break;
          case Event.typeCanceled:
            break;
        }
      });
    });
  }

  void assistBalanceOnOff(bool on) {
    protocol.assistBalanceOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("assistBalanceOnOff, successfully");
      } else {
        LogUtils.d("assistBalanceOnOff, error  " + rsp.error.toString());
      }
    });
  }

  void uploadAvatar() {
    var manager = protocol.createAvatarFileManager();

    getApplicationDocumentsDirectory().then((dir) {
      manager.uploadConfig(LorinAvatarFileConfig.create(
          dir.path + "/avatar/user.jpg",
          openFileTpe: IFileManager.openFileTypeReadWrite2));

      manager.upload().listen((event) {
        LogUtils.d('uploadAvatar, type: ${event.type}');
        switch (event.type) {
          case Event.typeFileTransferring:
            break;
          case Event.typeFileTransferFinished:
            break;
          case Event.typeCanceled:
            break;
        }
      });
    });
  }

  void requestLog() {
    var manager = protocol.createLogFileManager();

    getApplicationDocumentsDirectory().then((dir) {
      manager.config(manager.createLogConfig(dir.path + "/log/log.bin",
          target: DeviceUtils.getHmicDevice(_productProperty!.model),
          productProperty: _productProperty));

      manager.start().listen((event) {
        LogUtils.d('requestLog, type: ${event.type}');
        switch (event.type) {
          case log_file_manager.UploadEvent.typeFileTransferring:
            var transferringEvent =
                event as log_file_manager.FileTransferringEvent;
            LogUtils.d(
                "total: ${transferringEvent.total()}, progress: ${transferringEvent.progress()}");
            break;
          case Event.typeFileTransferFinished:
            break;
          case Event.typeCanceled:
            break;
        }
      }).onError((e) {
        if (e is CanceledError) {
          print("request log canceled.");
        }
        if (e is log_file_manager.UploadError) {
          if (e.isNotNowError()) {
            Prompt.showToast("Warning", "Motor is working!!!");
            print("Motor is working!!!");
            return;
          }
          print("Upload log failed, error: " + e.formatErrorCode(''));
        }
      });

      // Future.delayed(Duration(seconds: 5), () {
      //   manager.cancel();
      //   manager.destroy();
      // });
    });
  }

  void requestBMSLog() {
    var logManager = protocol.createBMSLogManager();
    getApplicationDocumentsDirectory().then((dir) {
      logManager.config(File(dir.path +
          "/bms-log/" +
          DateTime.now().millisecondsSinceEpoch.toString()));

      logManager.start().listen((event) {
        if (event is bms_log_manager.FinishedEvent) {
          print("request bms log finished. log files: ${event.logFiles}");
        } else {
          print(
              "request bms log, device: ${event.device}, index: ${event.index}, total: ${event.total}");
        }
      }).onError((e) {
        if (e is bms_log_manager.UploadError) {
          print(
              "upload error occurred, device: ${e.device}, index: ${e.index}, error: ${e.error}, error code: ${e.formatErrorCode('')}");
        } else {
          print("unknown error occurred, ${e.toString()}");
        }
      });
    });

    Future.delayed(Duration(milliseconds: 5000), () {
      logManager.cancel();
    });
  }

  Future<bool> onPageClose() {
    BleManager().disconnect();
    return Future.value(true);
  }

  void fixAirPro() async {
    var success =
        await setProductModel(0x32, ProductModel.fromHexCode("030705010100"));
    if (!success) Prompt.showToast("Fail", "Failed[1]");
    success = await setScooterSpeedLimit(2, 3600);
    if (!success) Prompt.showToast("Fail", "Failed[2]");
    Prompt.showToast("Success", "Succeed!");
  }

  Future<bool> setProductModel(int target, ProductModel model) async {
    Uint8ClampedList modelBytes = Uint8ClampedList.fromList([
      model.mainSeries.value,
      model.series.value,
      model.type.value,
      model.batch.value,
      model.feature.value,
      model.reverse.value
    ]);
    var msg = LorinGeneralMessageFactory.genGeneralMany2ManyMsg(
        0x01,
        target,
        Constant.channelInfo,
        Constant.PROPERTY_CHANNEL_INFO_CAR_TYPE | Constant.propertyTypeWrite,
        modelBytes);
    var rspMsg = await protocol.sendTransparentData(msg);
    var rspPara =
        ((rspMsg as LorinMessage).data as LorinGeneralMessageData).para;
    if (rspPara != null && rspPara[0] == 0) return Future.value(true);
    return Future(() => false);
  }

  Future<bool> setScooterSpeedLimit(int channel, int speed) async {
    Uint8ClampedList paramBytes = Uint8ClampedList(1 + 1 + 2);
    paramBytes[0] = channel;
    paramBytes[1] = 2;
    ByteUtil.num2BytesLe(speed, 2, paramBytes, 2);

    var msg = LorinGeneralMessageFactory.genGeneralMany2ManyMsg(
        0x01, 0x32, 1, 0x85, paramBytes);
    var rspMsg = await protocol.sendTransparentData(msg);
    var rspPara =
        ((rspMsg as LorinMessage).data as LorinGeneralMessageData).para;
    if (rspPara != null && rspPara.length > 1 && rspPara[1] == 0)
      return Future.value(true);
    return Future(() => false);
  }

  Future<List<EsimModel>> getEsimList() {
    return protocol.requestTBoxEsimList();
  }

  Future<TBoxInfo> requestTBoxRealTimeInfo() {
    return protocol.requestTBoxRealTimeInfo();
  }

  lowBatteryWakeUp(bool val) {
    return protocol.tboxLowBatLevelWakeUpVehicleModeOnOff(val).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("tboxLowBatLevelWakeUpVehicleMode, success");
        return;
      }
      LogUtils.d(
          "tboxLowBatLevelWakeUpVehicleMode, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when tboxLowBatLevelWakeUpVehicleMode", e);
    });
  }

  showTboxInfo(bool val) {
    return protocol.showTboxInfoOnVehicleOnOff(val).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("showTboxInfoOnVehicle, success");
        return;
      }
      LogUtils.d("showTboxInfoOnVehicle, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when showTboxInfoOnVehicle", e);
    });
  }

  safeSpeedLimitOnOff(bool on) {
    return protocol.safeSpeedLimitOnOff(on).then((rsp) {
      if (rsp.isSuccess()) {
        LogUtils.d("safeSpeedLimitOnOff, success");
        return;
      }
      LogUtils.d("safeSpeedLimitOnOff, failed, " + rsp.error.toString());
    }).catchError((e) {
      LogUtils.e("Error occurred when safeSpeedLimitOnOff", e);
    });
  }
}

class BleSendHandler extends SendHandler {
  @override
  void send(Uint8ClampedList bytes, [String clientId = 'default']) {
    BleManager().write(bytes.toList());
  }

  @override
  void post(Uint8ClampedList bytes, int? msgId,
      HttpSuccessCallback? httpCallback, HttpFailCallback? failCallback,
      [String clientId = 'default']) {
    succeedMap?['$msgId'] = httpCallback;
  }
}
